<?php


namespace App\Http\Controllers;

use App\Models\Activity;
use App\Models\ActivityApply;
use App\Models\ActivitySign;
use App\Models\Reservation;
use App\Models\ReservationApply;
use App\Models\ReservationSchedule;
use App\Models\ReservationSeat;
use App\Models\UserInfo;
use App\Models\UserLibraryInfo;
use App\Validate\ScanQrValidate;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 扫描二维码
 * Class SanQr
 * @package app\port\controller
 */
class ScanQrController extends Controller
{
    protected $validate = null;
    protected $user_id = null;
    protected $account_id = null;

    public function __construct()
    {
        parent::__construct();
        $this->validate = new ScanQrValidate();
    }

    /**
     * 扫描二维码
     * @param  qr_code  二维码code  固定前 2位 活动为 11   预约为 12  座位预约（座位号）为 13
     */
    public function scanAffirm()
    {
        //__construct 是在中间件前执行的，所以需要放在这里执行
        $user_id = request()->user_info['id'];
        $account_id = request()->user_info['account_id'];

        //增加验证场景进行验证
        if (!$this->validate->scene('scan_qr')->check(request()->all())) {
            return $this->returnApi(201,  $this->validate->getError());
        }

        Log::error('签到:' . json_encode(request()->all()));

        $qr_code = request()->input("qr_code", "");
        $prefix = substr($qr_code, 0, 2);

        //其他单独判断
        switch ($prefix) {
            case 11:
                return $this->scanActSign($qr_code, $user_id);
                break;
            case 12:
                return $this->scanReservationSign($qr_code, $user_id);//除座位预约外的其他预约
                break;
            case 13:
                return $this->scanSeatSign($qr_code, $user_id);//座位预约
                break;
            default:
                return $this->returnApi(202, "请扫描正确二维码");
        }
    }


    /**
     * 用户扫码签到 活动
     * @param $authorrization 用户 token    例：Bearer 1 必选
     * @param qr_code 活动code  固定前 2位 为 11
     */
    public function scanActSign($qr_code, $user_id)
    {
        /**是否自动报名 */
        $apply_is_auto = false;

        // 活动是否存在
        $act = Activity::select('id', 'title', 'end_time', 'is_apply', 'apply_number', 'is_long', 'start_time', 'end_time', 'everyday_start_time', 'everyday_end_time', 'is_reader')
            ->where("qr_code", $qr_code)
            ->where("is_del", 1)
            ->first();

        if (!$act)
            return $this->returnApi(202, "活动不存在或已被删除");
        // elseif ($act["is_apply"] == 2)
        //     return $this->returnApi(202, "该活动无须签到");
        elseif ($act['end_time'] < date("Y-m-d", strtotime("-1 days")))
            return $this->returnApi(202, '活动已经结束很久了,不能签到');

        // if ($act['is_apply'] == 1 && empty($res)) {
        //     return $this->returnApi(202, '暂未查询到报名信息或报名信息未审核通过,不能签到');
        // }

        $activityApplyObj = new ActivityApply();
        //报名需要审核的活动，需要先报名成功
        if ($act['is_apply'] == 1 || $act['is_check'] == 1) {
            // 查询用户报名信息
            $res = $activityApplyObj->select('id', 'status', 'sign_num')
                ->where('user_id', $user_id)
                ->where('act_id', $act['id'])
                ->orderByDesc('id')
                ->first();
            if (empty($res)) {
                return $this->returnApi(202, '暂无报名信息，请先报名');
            } elseif ($res['status'] != 1) {
                return $this->returnApi(202, '您的报名，未审核通过，暂不能签到');
            }
        }

        // 查询用户报名信息
        $res = $activityApplyObj->select('id', 'sign_num')
            ->where('user_id', $user_id)
            ->where('act_id', $act['id'])
            ->where('status', 1)
            ->orderByDesc('id')
            ->first();

        /**检查签到时间 */
        $date = time();
        //长期活动，在每日的开始前30分钟 ~ 结束的前30分钟为签到时间；短期活动，在活动的开始前30分钟 ~ 结束的前30分钟为签到时间；
        if ($act['is_long'] == 1) {
            if ($date < strtotime(date("Y-m-d") . ' ' . $act['everyday_start_time']) - 30 * 60 || $date >= strtotime(date("Y-m-d") . ' ' . $act['everyday_end_time']) - 30 * 60) {
                return $this->returnApi(202, '当前时间不在打卡范围内');
            }
        } else {
            if ($date < strtotime($act['start_time']) - 30 * 60 || $date >= strtotime($act['end_time']) - 30 * 60) {
                return $this->returnApi(202, '当前时间不在打卡范围内');
            }
        }

        //签到
        DB::beginTransaction();
        try {
            /**未查询到用户报名信息自动为用户报名 */
            if (!$res) {
                $user = UserInfo::find($user_id);

                $applyData = [
                    'user_id' => $user_id,
                    'act_id' => $act['id'],
                    'account_id' => $user['account_id'] ? $user['account_id'] : 0,
                    'status' => 1,
                ];

                $insert_res = $activityApplyObj->add($applyData);

                if ($insert_res === false) {
                    throw new Exception('签到失败,请稍后再试');
                }

                $res = $activityApplyObj->select('id', 'sign_num')
                    ->where('user_id', $user_id)
                    ->where('act_id', $act['id'])
                    ->where('status', 1)
                    ->orderByDesc('id')
                    ->first();

                //增加报名人数
                $act->apply_number = ++$act->apply_number;
                $act->save();

                $apply_is_auto = true;
            }


            //不是长期活动，只能签到一次
            if ($act->is_long == 2 && $res->sign_num > 0) {
                throw new Exception("您已签到，请勿重复签到");
            }


            //判断今日是否签到
            $activitySignModel = new ActivitySign();
            $day_sign = $activitySignModel
                ->where('act_id', $act['id'])
                ->where('apply_id', $res['id'])
                ->where('user_id', $user_id)
                ->where('date', date('Y-m-d'))
                ->first();
            if (!empty($day_sign)) {
                throw new Exception('今日已签到，请勿重复签到');
            }


            $res->sign_num = $res['sign_num'] + 1;
            $res->save();

            # 录入签到列表
            $activitySignData = [
                "act_id" => $act['id'],
                "apply_id" => $res['id'],
                "user_id" => $user_id,
                "date" => date("Y-m-d"),
                "yyy" => date("Y"),
                "mmm" => date("m"),
                "ddd" => date("d"),
            ];
            $activitySignModel->add($activitySignData);

            //用户积分操作  与 系统消息
            $system_id = $this->systemAdd('活动签到成功', $user_id, request()->user_info['account_id'], 15, $res['id'], '【' . $act['title'] . '】活动签到成功'); //添加系统消息

            /**积分 */
            if (config('other.is_need_score') && $apply_is_auto && $res->sign_num <= 1) {
                $userLibraryInfoModel = new UserLibraryInfo();
                $account_info = $userLibraryInfoModel->checkAccountPwdIsNormal($user_id);

                /**如果已绑定读者证 */
                if ($account_info) {
                    if ($act->is_reader == 1) {
                        $scoreRuleObj = new ScoreRuleController();
                        $score_status = $scoreRuleObj->checkScoreStatus(4, $account_info['id']);
                    }
                    /**执行积分规则 */
                    if ($score_status['code'] == 200) {
                        $system_id = $this->systemAdd($score_status['score_info']['type_name'], $user_id, $account_info['id'], 15, $res['id'], $score_status['score_info']['intro']);
                        $scoreRuleObj->scoreChange($score_status, $account_info['id'], $system_id); //添加积分消息
                    }
                }
            }
            // 提交事务
            DB::commit();
            return $this->returnApi(
                200,
                '活动:【' . $act['title'] . '】签到成功！',
                true
            );
        } catch (\Exception $e) {
            Log::error('签到错误:' . $e->getMessage() . ';错误文件：' . $e->getFile() . ';错误行数：' . $e->getLine());
            // 回滚事务
            DB::rollBack();
            //  return $this->returnApi(202, !empty($e->getMessage()) ? $e->getMessage() . $e->getFile() . $e->getLine() : '签到失败');
            return $this->returnApi(202, !empty($e->getMessage()) ? $e->getMessage() : '签到失败');
        }
    }



    /**
     * 用户扫码签到 预约 到馆（如果已预约其他，也可直接进入）
     */
    public function scanReservationSign($qr_code, $user_id)
    {
        $reservationObj = new Reservation();
        // 自动验证
        $reservation_info = $reservationObj->where('qr_code', $qr_code)->first();

        if (!$reservation_info) {
            return $this->returnApi(201, "此预约不存在或已被删除");
        }

        $reservation_id = $reservation_info->id;

        if ($reservation_info['is_sign'] == 2) {
            return $this->returnApi(202, "此预约无须签到");
        }

        $week = date("w");
        $weeks = $week ? $week : 7;

        //获取当前时间段对应的  预约时间段信息
        $reservationScheduleObj = new ReservationSchedule();
        $reservation_schedule = $reservationScheduleObj->getWeekScheduleInfo($reservation_id, $weeks);

        if (empty($reservation_schedule)) {
            return $this->returnApi(202, "当前时间段，无任何排版信息");
        }

        $reservationApplyModel = new ReservationApply();
        $apply = $reservationApplyModel->nowTimeMakeInfo($user_id, $reservation_id, $reservation_schedule->id, null, [1 , 6]);


        //如果是到馆预约的二维码，并且未预约到馆，可以查看其他 是否有预约
        if ($reservation_schedule && empty($apply) && $reservation_info->node == 5) {
            //查询这个时间段是否有其他预约(除到馆预约外的预约)
            $is_exists = $reservationObj->isExistsOtherMake($user_id, $weeks, [1, 2, 3, 4, 6]);
            if ($is_exists) {

                if ($is_exists['status'] == 1 && date('Y-m-d H:i:s') > $is_exists['expire_time']) {
                    return $this->returnApi(201, "当前时间段，未查询到任何预约信息"); // "已超过开始打卡时间，不能打卡"
                }

                return $this->returnApi(
                    200,
                    "查询成功,已预约“" . $reservationObj->getNodeName($is_exists['node']) . "”，时间段为:【" . date('Y-m-d') . ' ' . $is_exists['start_time'] . '~' . $is_exists['end_time'] . "】",
                    true
                ); //直接签到成功
            } else {
                //只是没查询到
                return $this->returnApi(201, "当前时间段，未查询到任何预约信息");
            }
        } elseif (empty($apply)) {
            //只是没查询到
            return $this->returnApi(201, "当前时间段，未查询到任何预约信息");
        }


        //判断是否过了打卡时间
        if ($apply->status == 1 && date('Y-m-d H:i:s') > $apply->expire_time) {
            return $this->returnApi(201, "当前时间段，未查询到任何预约信息");
        }

        // 启动事务
        DB::beginTransaction();
        try {
            $apply->status = 6;
            $apply->sign_time = date('Y-m-d H:i:s');
            $apply->save();

            $node_name = $reservationObj->getNodeName($reservation_info['node']);

            //用户积分操作  与 系统消息
            $this->systemAdd($node_name . '签到成功', $user_id, request()->user_info['account_id'], 16, $apply->id, '【' . $reservation_info->name . '】签到成功'); //添加系统消息

            // 提交事务
            DB::commit();
            return $this->returnApi(
                200,
                $node_name . ":【" . $reservation_info->name . "】签到成功；预约时间段为:【" . date('Y-m-d') . ' ' . $reservation_schedule['start_time'] . '~' . $reservation_schedule['end_time'] . "】",
                true
            ); //直接签到成功
        } catch (\Exception $e) {
            Log::error('签到错误:' . $e->getMessage() . ';错误文件：' . $e->getFile() . ';错误行数：' . $e->getLine());
            // 回滚事务
            DB::rollBack();
            return $this->returnApi(202, "签到失败");
        }
    }


    /**
     * 座位预约打卡签到
     * @param code string 二维码code
     */
    public function scanSeatSign($qr_code, $user_id)
    {
        $reservationApplyModel = new ReservationApply();
        $reservationSeatModel = new ReservationSeat();
        $seatInfo = $reservationSeatModel->where('qr_code', $qr_code)->first();

        if (!$seatInfo) {
            return $this->returnApi(201, "此座位不存在或已被删除");
        }

        $reservation_id = $seatInfo->reservation_id;
        $week = date("w");
        $weeks = $week ? $week : 7;

        /**检查是否在排班时间内 */
        $reservationScheduleObj = new ReservationSchedule();
        $reservation_schedule = $reservationScheduleObj->getWeekScheduleInfo($reservation_id, $weeks);

        if (empty($reservation_schedule)) {
            return $this->returnApi(202, "当前时间段，无任何排版信息");
        }

        /**查询该时段时候有申请记录 */
        $apply = $reservationApplyModel->nowTimeMakeInfo($user_id, $reservation_id, $reservation_schedule->id, $seatInfo->id, [1]);

        // if (empty($apply)) {
        //     return $this->returnApi(202, "当前时间段，未查询到任何预约信息");
        // }

        if(empty($apply)){
            //查询当前时间段是否已经签到
            $is_sign = $reservationApplyModel->nowTimeMakeInfo($user_id, $reservation_id, $reservation_schedule->id, $seatInfo->id, [6]);
            if($is_sign){
                return $this->returnApi(201, "已签到，请勿重复签到");
            }
            return $this->returnApi(202, "当前时间段，未查询到任何预约信息");
        }

        if ($apply->status == 1 && date('Y-m-d H:i:s') > strtotime($apply->expire_time)) {
            return $this->returnApi(201, "已超过开始打卡时间，不能打卡");
        }


        $msg = '';
        if ($apply->status == 1) {
            $apply->status = 6;
            $apply->sign_time = date("Y-m-d H:i:s", time());
            $msg = "签到成功";
        } else if ($apply->status == 6) {
            $apply->status = 7; //已签退
            $apply->sign_end_time = date("Y-m-d H:i:s", time());
            $msg = "签退成功";
        } else if ($apply->status == 7) {
            return $this->returnApi(201, "已成功结束打卡,请勿重复打卡");
        }
        DB::beginTransaction();
        try {
            $apply->save();

            //用户积分操作  与 系统消息
            $reservation_name = Reservation::where('id', $reservation_id)->value('name');
            $this->systemAdd('座位预约' . $msg, $user_id, request()->user_info['account_id'], 16, $reservation_id, '【' . $reservation_name . '】' . $msg); //添加系统消息

            DB::commit();
            return $this->returnApi(
                200,
                "座位预约:【" . $reservation_name . "】" . $msg . ";预约时间段为:【" . date('Y-m-d') . ' ' . $reservation_schedule['start_time'] . '~' . $reservation_schedule['end_time'] . "】",
                true
            );
        } catch (\Exception $e) {
            Log::error('签到错误:' . $e->getMessage() . ';错误文件：' . $e->getFile() . ';错误行数：' . $e->getLine());
            DB::rollBack();
            return $this->returnApi(202, "打卡失败,请稍后再试");
        }
    }
}
